package wtflog

import (
	"unicode/utf8"

	. "gitee.com/FlyingOnion/wtflog/types"
)

func isInsecureCharacter(c byte) bool {
	return c < 32 || c == '\\' || c == '"'
}

var hex = "0123456789abcdef"

// appendJsonSafeString converts strings with json syntax to safe strings (by adding a '\\' prefix)
func appendJsonSafeString(b *ByteSlice, s string) {
	i := 0
	for j := 0; j < len(s); {
		if c := s[j]; c < utf8.RuneSelf {
			if !isInsecureCharacter(c) {
				j++
				continue
			}
			if i < j {
				b.AppendString(s[i:j])
			}
			b.AppendByte('\\')
			switch c {
			case '\\', '"':
				b.AppendByte(c)
			case '\n':
				b.AppendByte('n')
			case '\r':
				b.AppendByte('r')
			case '\t':
				b.AppendByte('t')
			default:
				b.AppendString("u00").AppendByte(hex[c>>4]).AppendByte(hex[c&0xF])
			}
			j++
			i = j
			continue
		}
		c, size := utf8.DecodeRuneInString(s[j:])
		if c == utf8.RuneError && size == 1 {
			if i < j {
				b.AppendString(s[i:j])
			}
			b.AppendString(`\ufffd`)
			j += size
			i = j
			continue
		}
		if c == '\u2028' || c == '\u2029' {
			if i < j {
				b.AppendString(s[i:j])
			}
			b.AppendString(`\u202`).AppendByte(hex[c&0xF])
			j += size
			i = j
			continue
		}
		j += size
	}
	if i < len(s) {
		b.AppendString(s[i:])
	}
}

// appendJsonSafeBytes converts strings with json syntax to safe strings (by adding a '\\' prefix)
func appendJsonSafeBytes(b *ByteSlice, s []byte) {
	i := 0
	for j := 0; j < len(s); {
		if c := s[j]; c < utf8.RuneSelf {
			if !isInsecureCharacter(c) {
				j++
				continue
			}
			if i < j {
				b.AppendBytes(s[i:j])
			}
			b.AppendByte('\\')
			switch c {
			case '\\', '"':
				b.AppendByte(c)
			case '\n':
				b.AppendByte('n')
			case '\r':
				b.AppendByte('r')
			case '\t':
				b.AppendByte('t')
			default:
				b.AppendString("u00").AppendByte(hex[c>>4]).AppendByte(hex[c&0xF])
			}
			j++
			i = j
			continue
		}
		c, size := utf8.DecodeRune(s[j:])
		if c == utf8.RuneError && size == 1 {
			if i < j {
				b.AppendBytes(s[i:j])
			}
			b.AppendString(`\ufffd`)
			j += size
			i = j
			continue
		}
		if c == '\u2028' || c == '\u2029' {
			if i < j {
				b.AppendBytes(s[i:j])
			}
			b.AppendString(`\u202`).AppendByte(hex[c&0xF])
			j += size
			i = j
			continue
		}
		j += size
	}
	if i < len(s) {
		b.AppendBytes(s[i:])
	}
}
